home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
pcb-1.000
/
pcb-1
/
pcb-1.3
/
undo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
14KB
|
553 lines
/*
* COPYRIGHT
*
* PCB, interactive printed circuit board design
* Copyright (C) 1994,1995 Thomas Nau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact addresses for paper mail and Email:
* Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
* Thomas.Nau@rz.uni-ulm.de
*
*/
static char *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/undo.c,v 1.1 1995/01/14 18:29:08 nau Exp nau $";
/* functions used to undo operations
*
* Description:
* There are two lists which hold
* - information about a command
* - data of removed objects
* Both lists are organized as first-in-last-out which means that the undo
* list can always use the last entry of the remove list.
* A serial number is incremented whenever an operation is completed.
* An operation itself may consist of several basic instructions.
* E.g.: removing all selected objects is one operation with exactly one
* serial number even if the remove function is called several times.
*
* a lock flag ensures that no infinite loops occure
*/
#include <memory.h>
#include "global.h"
#include "buffer.h"
#include "change.h"
#include "create.h"
#include "data.h"
#include "draw.h"
#include "error.h"
#include "mymem.h"
#include "misc.h"
#include "move.h"
#include "polygon.h"
#include "remove.h"
#include "search.h"
#include "set.h"
#include "undo.h"
/* ---------------------------------------------------------------------------
* some local defines
*/
#define SIZE_LIMIT (100*1024) /* warning limit 100k */
/* ---------------------------------------------------------------------------
* some local data types
*/
typedef struct /* information about a change command */
{
char *Name;
} ChangeNameType, *ChangeNameTypePtr;
typedef struct /* information about a move command */
{
Position DX, /* movement vector */
DY;
} MoveType, *MoveTypePtr;
typedef struct /* information about removed polygon points */
{
PolygonPointType Point; /* data */
Cardinal Index; /* index in polygons array of points */
} RemovedPointType, *RemovedPointTypePtr;
typedef struct /* information about inserted polygon points */
{
int ID; /* ID of inserted point */
} InsertedPointType, *InsertedPointTypePtr;
typedef struct /* holds information about an operation */
{
int Serial, /* serial number of operation */
Type, /* type of operation */
ID; /* object ID */
union /* some additional information */
{
ChangeNameType ChangeName;
MoveType Move;
RemovedPointType RemovedPoint;
InsertedPointType InsertedPoint;
} Data;
} UndoListType, *UndoListTypePtr;
/* ---------------------------------------------------------------------------
* some local identifiers
*/
static DataTypePtr RemoveList; /* list of removed objects */
static UndoListTypePtr UndoList; /* list of operations */
static int Serial; /* serial number */
static size_t UndoN, /* number of entries */
UndoMax;
static Boolean Locked = False; /* do not add entries if */
/* flag is set; prevents from */
/* infinite loops */
/* ---------------------------------------------------------------------------
* some local prototypes
*/
static UndoListTypePtr GetUndoSlot(int, int);
static void DrawRecoveredObject(int, void *, void *);
static Boolean UndoChangeName(UndoListTypePtr);
static Boolean UndoCopy(UndoListTypePtr);
static Boolean UndoMove(UndoListTypePtr);
static Boolean UndoRemove(UndoListTypePtr);
static Boolean UndoRemovePolygonPoint(UndoListTypePtr);
static Boolean UndoInsertPolygonPoint(UndoListTypePtr);
/* ---------------------------------------------------------------------------
* adds a command plus some data to the undo list
*/
static UndoListTypePtr GetUndoSlot(int CommandType, int ID)
{
UndoListTypePtr ptr;
static size_t limit = SIZE_LIMIT;
/* allocate memory */
if (UndoN >= UndoMax)
{
size_t size;
UndoMax += STEP_UNDOLIST;
size = UndoMax *sizeof(UndoListType);
UndoList = (UndoListTypePtr) MyRealloc(UndoList, size,
"AddCommandToUndoList()");
memset(&UndoList[UndoN], 0, STEP_REMOVELIST *sizeof(UndoListType));
/* ask user to flush the table because of it's size */
if (size > limit)
{
limit = (size /SIZE_LIMIT +1) *SIZE_LIMIT;
Message(False, "size of 'undo-list' exceeds %li kb\n",
(long) (size >> 10));
}
}
/* copy typefield and serial number to the list */
ptr = &UndoList[UndoN++];
ptr->Type = CommandType;
ptr->ID = ID;
ptr->Serial = Serial;
return(ptr);
}
/* ---------------------------------------------------------------------------
* redraws the recovered object
*/
static void DrawRecoveredObject(int Type, void *Ptr1, void *Ptr2)
{
if (Type & (LINE_TYPE | TEXT_TYPE | POLYGON_TYPE))
{
LayerTypePtr layer;
layer= &PCB->Data->Layer[GetLayerNumber(RemoveList,(LayerTypePtr)Ptr1)];
if (layer->On)
switch(Type)
{
case LINE_TYPE:
DrawLine(layer, (LineTypePtr) Ptr2);
break;
case TEXT_TYPE:
DrawText(layer, (TextTypePtr) Ptr2);
break;
case POLYGON_TYPE:
DrawPolygon(layer, (PolygonTypePtr) Ptr2);
break;
}
}
else
switch(Type)
{
case ELEMENT_TYPE:
if (PCB->ElementOn)
DrawElement((ElementTypePtr) Ptr2);
break;
case ELEMENTNAME_TYPE:
if (PCB->ElementOn)
DrawElementName((ElementTypePtr) Ptr1);
break;
case PIN_TYPE:
if (PCB->PinOn)
DrawPin((PinTypePtr) Ptr2);
break;
case VIA_TYPE:
if (PCB->ViaOn)
DrawVia((PinTypePtr) Ptr2);
break;
}
}
/* ---------------------------------------------------------------------------
* recovers an object from a 'change name' operation
* returns True if anything has been recovered
*/
static Boolean UndoChangeName(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
int type;
/* lookup entry by it's ID */
type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
if (type != NO_TYPE)
{
SaveFree(ChangeObjectName(type, ptr1, ptr2,
Entry->Data.ChangeName.Name));
return(True);
}
return(False);
}
/* ---------------------------------------------------------------------------
* recovers an object from a 'copy' operation
* returns True if anything has been recovered
*/
static Boolean UndoCopy(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
int type;
/* lookup entry by it's ID */
type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
if (type != NO_TYPE)
{
DestroyObject(type, ptr1, ptr2);
return(True);
}
return(False);
}
/* ---------------------------------------------------------------------------
* recovers an object from a 'move' operation
* returns True if anything has been recovered
*/
static Boolean UndoMove(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
int type;
/* lookup entry by it's ID */
type = SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID);
if (type != NO_TYPE)
{
MoveObject(type,ptr1,ptr2, -Entry->Data.Move.DX, -Entry->Data.Move.DY);
return(True);
}
return(False);
}
/* ----------------------------------------------------------------------
* recovers an object from a 'remove' operation
* returns True if anything has been recovered
*/
static Boolean UndoRemove(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
int type;
/* lookup entry by it's ID */
type = SearchObjectByID(RemoveList, &ptr1, &ptr2, Entry->ID);
if (type != NO_TYPE)
{
DrawRecoveredObject(type, ptr1, ptr2);
MoveObjectToBuffer(PCB->Data, RemoveList, type, ptr1, ptr2);
return(True);
}
return(False);
}
/* ---------------------------------------------------------------------------
* recovers a removed polygon point
* returns true on success
*/
static Boolean UndoRemovePolygonPoint(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
/* lookup entry (polygon not point was saved) by it's ID */
if (SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID) == POLYGON_TYPE)
{
LayerTypePtr layer = (LayerTypePtr) ptr1;
PolygonTypePtr polygon = (PolygonTypePtr) ptr2;
/* recover the point */
if (layer->On)
{
ErasePolygon(polygon);
InsertPointIntoPolygon(polygon, Entry->Data.RemovedPoint.Index,
Entry->Data.RemovedPoint.Point.X,
Entry->Data.RemovedPoint.Point.Y);
DrawPolygon(layer, polygon);
}
else
InsertPointIntoPolygon(polygon, Entry->Data.RemovedPoint.Index,
Entry->Data.RemovedPoint.Point.X,
Entry->Data.RemovedPoint.Point.Y);
return(True);
}
return(False);
}
/* ---------------------------------------------------------------------------
* recovers an inserted polygon point
* returns true on success
*/
static Boolean UndoInsertPolygonPoint(UndoListTypePtr Entry)
{
void *ptr1, *ptr2;
/* lookup entry (polygon not point was saved) by it's ID */
if (SearchObjectByID(PCB->Data, &ptr1, &ptr2, Entry->ID) == POLYGON_TYPE)
{
PolygonTypePtr polygon = (PolygonTypePtr) ptr2;
/* lookup point by it's ID */
POLYGONPOINT_LOOP(polygon,
if (point->ID == Entry->Data.InsertedPoint.ID)
{
RemovePolygonPoint(polygon, point);
return(True);
}
);
}
return(False);
}
/* ---------------------------------------------------------------------------
* undo of any 'hard to recover' operation
* supported are MOVE, CREATE, REMOVE and CHANGENAME
*
* returns True if anything is has been done
*/
Boolean Undo(void)
{
UndoListTypePtr ptr;
Boolean changed = False;
if (!UndoN)
return(False);
/* lock undo module to prevent from loops
* and loop over all entries with the same serial number
*/
LockUndo();
ptr = &UndoList[UndoN -1];
Serial = ptr->Serial;
for (; UndoN && ptr->Serial == Serial; ptr--, UndoN--)
switch(ptr->Type)
{
case UNDO_CHANGENAME:
changed |= UndoChangeName(ptr);
break;
case UNDO_COPY:
changed |= UndoCopy(ptr);
break;
case UNDO_MOVE:
changed |= UndoMove(ptr);
break;
case UNDO_REMOVE:
changed |= UndoRemove(ptr);
break;
case UNDO_REMOVE_POLYGON_POINT:
changed |= UndoRemovePolygonPoint(ptr);
break;
case UNDO_INSERT_POLYGON_POINT:
changed |= UndoInsertPolygonPoint(ptr);
break;
}
/* release lock */
UnlockUndo();
return(changed);
}
/* ---------------------------------------------------------------------------
* increments the serial number of the undo list
* it's not done automatically because some operations perform more
* than one request with the same serial #
*/
void IncrementUndoSerialNumber(void)
{
if (!Locked)
Serial++;
}
/* ---------------------------------------------------------------------------
* releases memory of the undo- and remove list
*/
void ClearUndoList(void)
{
UndoListTypePtr undo;
/* release memory allocated by objects in undo list */
for (undo = UndoList; UndoN; undo++, UndoN--)
if (undo->Type == UNDO_CHANGENAME)
SaveFree(undo->Data.ChangeName.Name);
MyFree((char **) &UndoList);
FreeDataMemory(RemoveList);
/* reset some counters */
UndoN = UndoMax = 0;
Serial = 0;
}
/* ---------------------------------------------------------------------------
* adds an object to the list of removed objects and removes it from
* the current PCB
*/
void MoveObjectToRemoveUndoList(int Type, void *Ptr1, void *Ptr2)
{
UndoListTypePtr undo;
if (!Locked)
{
if (!RemoveList)
RemoveList = CreateNewBuffer();
undo = GetUndoSlot(UNDO_REMOVE, OBJECT_ID(Ptr2));
MoveObjectToBuffer(RemoveList, PCB->Data, Type, Ptr1, Ptr2);
}
}
/* ---------------------------------------------------------------------------
* adds an object to the list of removed polygon points
*/
void AddObjectToRemovePolygonPointUndoList(PolygonTypePtr Polygon,
PolygonPointTypePtr Point)
{
UndoListTypePtr undo;
if (!Locked)
{
/* the ID of the polygon is used instead */
undo = GetUndoSlot(UNDO_REMOVE_POLYGON_POINT, Polygon->ID);
undo->Data.RemovedPoint.Point = *Point;
/* get index in array of points */
POLYGONPOINT_LOOP(Polygon,
if (point == Point)
{
undo->Data.RemovedPoint.Index = n;
break;
}
);
}
}
/* ---------------------------------------------------------------------------
* adds an object to the list of inserted polygon points
*/
void AddObjectToInsertPolygonPointUndoList(PolygonTypePtr Polygon,
PolygonPointTypePtr Point)
{
UndoListTypePtr undo;
if (!Locked)
{
/* the ID of the polygon is used instead */
undo = GetUndoSlot(UNDO_INSERT_POLYGON_POINT, Polygon->ID);
undo->Data.InsertedPoint.ID = Point->ID;
}
}
/* ---------------------------------------------------------------------------
* adds an object to the list of copied objects
*/
void AddObjectToCopyUndoList(int Type, void *Ptr1, void *Ptr2)
{
UndoListTypePtr undo;
if (!Locked)
undo = GetUndoSlot(UNDO_COPY, OBJECT_ID(Ptr2));
}
/* ---------------------------------------------------------------------------
* adds an object to the list of moved objects
*/
void AddObjectToMoveUndoList(int Type, void *Ptr1, void *Ptr2,
Position DX, Position DY)
{
UndoListTypePtr undo;
if (!Locked)
{
undo = GetUndoSlot(UNDO_MOVE, OBJECT_ID(Ptr2));
undo->Data.Move.DX = DX;
undo->Data.Move.DY = DY;
}
}
/* ---------------------------------------------------------------------------
* adds an object to the list of objects with changed names
*/
void AddObjectToChangeNameUndoList(int Type, void *Ptr1, void *Ptr2,
char *OldName)
{
UndoListTypePtr undo;
if (!Locked)
{
undo = GetUndoSlot(UNDO_CHANGENAME, OBJECT_ID(Ptr2));
undo->Data.ChangeName.Name = OldName;
}
}
/* ---------------------------------------------------------------------------
* set lock flag
*/
void LockUndo(void)
{
Locked = True;
}
/* ---------------------------------------------------------------------------
* reset lock flag
*/
void UnlockUndo(void)
{
Locked = False;
}